<?php
# @Author: 魏巍
# @Date:   2017-11-16T17:42:05+08:00
# @Email:  524314430@qq.com
# @Last modified by:   魏巍
# @Last modified time: 2017-11-18T17:37:51+08:00

namespace app\first\controller;

use app\admin\model\File;
use app\admin\model\Pic;
use app\admin\model\UploadType;
use app\common\model\Qiniu as qiNiuModel;
use Curl\Curl;
use Qiniu\Storage\BucketManager;
use Qiniu\Storage\UploadManager;
use Qiniu\Auth;
use think\Controller;
use think\facade\Cache;
use think\facade\Config;

class Qiniu extends Controller {
    private $auth = null;
    private $bucket = null;
    private $upload = '';

    /**
     * Qiniu constructor.
     * @param string $bucket
     * @param string $upload
     */
    public function __construct($bucket='',$upload=''){
        parent::__construct(null);
        $this->bucket = $bucket ? $bucket : Config::get('qiniu.bucket');
        $this->upload = $upload ? $upload : Config::get('qiniu.upload');
        $this->auth = new Auth(Config::get('qiniu.accessKey'),Config::get('qiniu.secretKey'));
    }

    /**
     * 获取上传token
     * @param int $type
     * @return array
     */
    public function qiNiuAccess($type=1){
        $info = (new UploadType())->get($type);
        $this->bucket = $info?$info['bucket']:$this->bucket;
        $body = [
            'key'=>'$(key)',
            'name'=>'$(fname)',
            'size'=>'$(fsize)',
            'type'=>$type,
            "mime"=>'$(mimeType)',
            "w"=>'$(imageInfo.width)',
            "h"=>'$(imageInfo.height)',
            "hash"=>'$(etag)',
        ];
        $policy = array(
            'callbackUrl' => Config::get('qiniu.callback'),
            'callbackBody' => json_encode($body),
            'fsizeLimit'=> 1024 * 1024 * 10
        );
        $token = $this->auth->uploadToken($this->bucket,null, 3600,$policy);
//        $_token = Cache::get('qiniu_token');
//        if($_token){
//            $token = $_token;
//        }else{
//            $token = $this->auth->uploadToken($this->bucket,null, 3600,$policy);
//            Cache::set('qiniu_token',$token,3600);
//        }
        return ['status'=>1,'token'=>$token,'upload'=>$this->upload];
    }

    /**
     * @param string $key   文件名
     * @return mixed
     */
    public function qiNiuFileInfo($key=''){
        $bucketManager = new BucketManager($this->auth);
        list($fileInfo, $err) = $bucketManager->stat($this->bucket, $key);
        if($err){
            return ['status'=>0,'msg'=>$err];
        }
        return ['status'=>1,'msg'=>'获取成功','data'=>$fileInfo];
    }

    /**
     * @param string $old_name
     * @param string $new_name
     * @return array|mixed
     */
    public function qiNiuRename($old_name='',$new_name=''){
        $bucketManager = new BucketManager($this->auth);
        $err = $bucketManager->move($this->bucket, $old_name, $this->bucket, $new_name, true);
        if($err){
            return $err;
        }
        return ['status'=>1,'msg'=>'操作成功'];
    }

    /**
     * 移动文件
     * @param string $filename      移动文件名
     * @param string $new_bucket    移动的目标bucket
     * @param string $new_name      移动文件重命名
     * @param string $old_bucket    移动的源bucket
     * @return array|mixed
     */
    public function qiNiuMove($filename='',$new_bucket='',$new_name='',$old_bucket=''){
        $old_bucket = $old_bucket?:$this->bucket;
        $new_name = $new_name?:$filename;
        $bucketManager = new BucketManager($this->auth);
        $err = $bucketManager->move($old_bucket, $filename, $new_bucket, $new_name, true);
        if($err){
            return $err;
        }
        return ['status'=>1,'msg'=>'操作成功'];
    }

    /**
     * 复制文件
     * @param string $filename      复制文件名
     * @param string $new_bucket    复制的目标bucket
     * @param string $new_name      复制文件重命名
     * @param string $old_bucket    复制的源bucket
     * @return array|mixed
     */
    public function qiNiuCopy($filename='',$new_bucket='',$new_name='',$old_bucket=''){
        $old_bucket = $old_bucket?:$this->bucket;
        $new_name = $new_name?:$filename;
        $bucketManager = new BucketManager($this->auth);
        $err = $bucketManager->copy($old_bucket, $filename, $new_bucket, $new_name, true);
        if($err){
            return $err;
        }
        return ['status'=>1,'msg'=>'操作成功'];
    }

    /**&
     * 删除文件
     * @param string $key
     * @param int $type
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function qiNiuDelete($key='',$type=1){
        if(!$key){
            return ['status'=>0,'msg'=>'缺少参数'];
        }
        if($type==1){
            $info = (new Pic())->getOneByKey($key);
        }else{
            $info = (new File())->getOneByKey($key);
        }
        if(!$info){
            return ['status'=>0,'msg'=>'目标不存在或已删除'];
        }
        $bucket = $info['bucket']?:$this->bucket;
        $bucketManager = new BucketManager($this->auth);
        if(!$info->delete()){
            return ['status'=>1,'msg'=>'删除失败'];
        }
        $err = $bucketManager->delete($bucket, $info['name']);
        if($err){
            return ['status'=>1,'msg'=>'删除失败'];
        }
        return ['status'=>1,'msg'=>'操作成功'];
    }

    /**
     * 批量删除
     * @param array $filename
     * @param string $bucket
     * @return array
     */
    public function qiNiuDeleteAll($filename=[],$bucket=''){
        if(count($filename)>1000){
            return ['status'=>0,'msg'=>'单次最多处理1000条'];
        }
        $bucket = $bucket?:$this->bucket;
        $bucketManager = new BucketManager($this->auth);
        $ops = $bucketManager->buildBatchDelete($bucket, $filename);
        list($ret, $err) = $bucketManager->batch($ops);
        if($err){
            return $err;
        }
        return ['status'=>1,'msg'=>'操作成功','data'=>$ret];
    }

    /**
     * @param int $limit
     * @param string $bucket
     * @return mixed
     * @throws \Exception
     */
    public function listFiles($limit=100,$bucket=''){
        $bucket = $bucket?$bucket:$this->bucket;
        $bucketManager = new BucketManager($this->auth);
        $prefix = '';
        $marker = '';
        $delimiter = '/';
        list($ret, $err) = $bucketManager->listFiles($bucket, $prefix, $marker, $limit, $delimiter);
        if ($err !== null) {
            throw new \Exception($err);
        }
        return $ret['items'];
    }

    /**
     * 百度ueditor编辑器上传图片
     * @param string $filename
     * @return \think\response\Json
     * @throws \Exception
     */
    public function uploadEditor($filename="upfile"){
        $action = $_GET['action'];
        $fileName = '';
        $type = $action=='uploadvideo'?2:1;
        $arr = ['state'=> '没有上传文件'];
        if($_FILES){
            $_file = $_FILES[$filename];
            $tmp = explode('.',$_file['name']);
            $ext = end($tmp);
            $fileName = $_file['name'];
            $arr = array(
                'state'=>'SUCCESS',
                'original'=>$fileName,
                'type'=>$ext,
                'size'=>$_file['size']
            );
        }
        switch ($action){
            case 'listimage':
                $p = input('start',1,'intval');
                $limit = input('size',20,'intval');
                $pic = new Pic();
                $list = $pic->getList($p,$limit);
                $data = [];
                $total = $pic->count('*');
                foreach($list as $k => $v){
                    $data[$k]['url'] = $v['picurl'];
                    $data[$k]['mtime'] = strtotime($v['create_time']);
                }
                $arr = array(
                    'state'=>'SUCCESS',
                    'list'=>$data,
                    'start'=>$p,
                    'total'=>$total
                );
                $result = json_encode($arr);
                break;
            case 'listfile':
                $p = input('start',1,'intval');
                $limit = input('size',20,'intval');
                $file = new File();
                $list = $file->getList($p,$limit);
                $total = $file->count('*');
                $data = [];
                foreach($list as $k => $v){
                    $data[$k]['url'] = $v['picurl'];
                    $data[$k]['mtime'] = strtotime($v['create_time']);
                }
                $arr = array(
                    'state'=>'SUCCESS',
                    'list'=>$data,
                    'start'=>$p,
                    'total'=>$total
                );
                $result = json_encode($arr);
                break;
            case 'uploadimage':
            case 'uploadvideo':
                $_result = $this->toQiNiu($filename,$type);
                if($_result['status']){
                    $arr['url']=$_result['data']['path'];
                    $arr['title']=$fileName;
                }
                $result = json_encode($arr);
                break;
            case 'config':
            default:
                $config = json_decode(preg_replace("/\/\*[\s\S]+?\*\//", "",
                    file_get_contents("./static/config.json")), true);
                $result =  json_encode($config);
                break;
        }
        /* 输出结果 */
        if (isset($_GET["callback"])) {
            if (preg_match("/^[\w_]+$/", $_GET["callback"])) {
                echo htmlspecialchars($_GET["callback"]) . '(' . $result . ')';
            } else {
               echo json(['state'=> 'callback参数不合法']);
            }
        } else {
            echo $result;
        }
    }

    /**
     * 上传七牛
     * @param string $file
     * @param int $type
     * @param string $bucket
     * @return array
     * @throws \Exception
     */
    public function toQiNiu($file='file',$type=1,$bucket=''){
        $bucket = $bucket ?: $this->bucket;
        $upManager = new UploadManager();
        $token = Cache::store(Config::get('qiniu.store'))
            ->get('qiniu_access_token');
        if(!$token){
            $token = $this->auth->uploadToken($bucket);
            Cache::store(Config::get('qiniu.store'))
                ->set('qiniu_access_token',$token,3600);
        }
        $config=Config::get('qiniu.validate');
        $file = request()->file($file);
        $info = $file->getInfo();
        if(!$file->checkSize($config['size'])){
            return ['status'=>0,'msg'=>'上传大小超过5M'];
        }
        if(!$file->checkExt($config['ext'])){
            return ['status'=>0,'msg'=>'不允许的上传类型'];
        }
        list($ret, $error) = $upManager->putFile($token,md5(microtime(true)),$file->getInfo()['tmp_name']);
        if($error){
            return ['status'=>0,'msg'=>"上传失败:{$error}"];
        }
        $path = Config::get('qiniu.domain').$ret['key'];
        $curl = new Curl();
        $curl->get("{$path}?imageInfo");
        if($curl->error){
            return ['status'=>0,'msg'=>'上传失败'];
        }
        $result = \Qiniu\json_decode($curl->response,true);
        $curl->close();
        $pic = new qiNiuModel();
        $res = $pic->addNew($info['name'],$path,$result['size'],$result['width'],$result['height'],$result['format'],$type,$out);
        if(!$res){
            return ['status'=>0,'msg'=>$out];
        }
        return ['status'=>1,'msg'=>'上传成功','data'=>['pic_id'=>$out,'path'=>$path]];
    }

    /**
     * 七牛回调
     * @return array
     * @throws \Exception
     */
    public function qiNiuCallBack(){
        $contentType = 'application/x-www-form-urlencoded';
        $callbackBody = file_get_contents('php://input');
        $authorization = $_SERVER['HTTP_AUTHORIZATION'];
        $url = Config::get('qiniu.callback');
        $isQiniuCallback = $this->auth->verifyCallback($contentType, $authorization, $url, $callbackBody);
        if($isQiniuCallback){
            $body = \Qiniu\json_decode($callbackBody, true);
            $type = $body['type']?$body['type']:1;
            $info = (new UploadType())->get($type);
            if(strpos($body['mime'],'image')!==false){
                $model = new Pic();
            }else{
                $model = new File();
            }
            $finder = $info['finder']?'!'.$info['finder']:'';
            $url = "{$info['domain']}{$body['key']}{$finder}";
            $mime = str_replace('%2F','/',$body['mime']);
            $id = $model->addNew($body['key'],$url,$mime,$body['w'],$body['h'],$body['size'],$type);
            if($id){
                return json(['status'=>1,'msg'=>'上传成功','data'=>['id'=>intval($id),'url'=>$url]]);
            }else{
                return json(['status'=>0,'msg'=>'上传失败']);
            }
        }else{
            return json(['status'=>0,'msg'=>'上传失败']);
        }
    }

    /**
     * 下载文件
     * @param string $filename
     */
    public function download($filename=''){
        $signedUrl = $this->auth->privateDownloadUrl($filename);
        echo $signedUrl;
    }
}
